#include "Integer.hpp"
#include "WordList.hpp"
#include <map>
#include <iostream>
#include <vector>


Integer::Integer(int n):
	integer(n)
{
	parse();
}

Integer::Integer():
	integer(0)
{
	parse();
}

void Integer::setValue(int setvalue){
    if(setvalue<0 || setvalue>1000){
        integer = -1;
		word = "INVALID";
		roman = "INVALID";
    }else{
        integer=setvalue;
        parse();

    }
}

bool Integer::parse()
{
	if ( integer < 0 || integer > 1000 )
	{
		integer = -1;
		word = "INVALID";
		roman = "INVALID";
		return false;
	}


	word = toWordNumberOperation(integer);

    while ( word[word.length()-1] == ' ')
    {
        word.erase(word.length()-1,1);
    }

	roman = toRomanNumeralOperation(integer);

	return true;
}

int Integer::toInteger() const
{
	return integer;
}

 std::string Integer::toRomanNumeral() const
{
	return roman;
}

 std::string Integer::toWordNumber() const
{
	return word;
}

std::string Integer::toWordNumberOperation(int x, int p)
{
	std::vector<std::string> wordList = WordList::generateWordList();
	std::string s = "";

	if ( x == 0 && p == 0 )
	{
		return "zero";
	}
	else if ( x > 0 )
	{
		s = toWordNumberOperation(x/10, p+1);

		if ( p == 0)
		{
			if ( s.length() >= 1 && s[s.length()-1] == '!' )
			{
				s.erase(s.length()-1,1);
				return s + wordList[(x % 10) + 10];
			}
			if ( x%10 == 0 ) return s + "";
			else return s + wordList[x % 10];
		}
		else if ( p == 1 )
		{
			if ( x%10 == 0 ) return s + "";
			else if ( x%10 == 1 ) return s + "!";
			else return s + wordList[(x % 10) + 18] + " ";
		}
		else if ( p == 2 )
		{
			if ( x%10 == 0 ) return s + "";
			else return wordList[(x % 10)] + " hundred ";
		}
		else if ( p == 3 )
		{
			return "one thousand ";
		}
		else
		{
			return "INVALID";
		}
	}
	else
	{
		return "";
	}
	return "";
}

std::string Integer::toRomanNumeralOperation(int x, int p)
{
	std::string s = "";

	if ( x == 0 && p == 0 )
	{
		return "";
	}

	else if ( x > 0 )
	{
		s = toRomanNumeralOperation(x/10, p+1);

		RomanToValueMap romanEquivalent = WordList::generateRomanValueMap();

		if ( p == 0 )
		{
			if ( x%10 == 0 ){ return s + "";}
			else
			{
				return s+romanEquivalent.find(x%10)->second;
			}
		}
		else if ( p == 1 )
		{
			if ( x%10 == 0 ) return s + "";
            else
			{
				return s+romanEquivalent.find((x%10)*10)->second;
			}
		}
		else if ( p == 2 )
		{
			if ( x%10 == 0 ) return s + "";
			else
			{
				return s+romanEquivalent.find((x%10)*100)->second;
			}
		}
		else if ( p == 3 )
		{
			return s+romanEquivalent.find((x%10)*1000)->second;
		}
		else
		{
			return "";
		}
	}
	else
	{
		return "";
	}
	return "";
}

bool Integer::operator>(const Integer& rhs) const
{
	Integer lhs = *this;
	if ((lhs.integer == -1 && rhs.integer != -1) ||
		(lhs.integer != -1 && rhs.integer == -1))
	{
		return false;
	}
	return lhs.integer > rhs.integer;
}
bool Integer::operator<(const Integer& rhs) const
{
	Integer lhs = *this;
	if ((lhs.integer == -1 && rhs.integer != -1) ||
		(lhs.integer != -1 && rhs.integer == -1))
	{
		return false;
	}
	return lhs.integer < rhs.integer;
}
bool Integer::operator>=(const Integer& rhs) const
{
	Integer lhs = *this;
	if ((lhs.integer == -1 && rhs.integer != -1) ||
		(lhs.integer != -1 && rhs.integer == -1))
	{
		return false;
	}
	if(lhs.integer == -1 && rhs.integer == -1)
        return true;
	return lhs.integer >= rhs.integer;
}
bool Integer::operator<=(const Integer& rhs) const
{
	Integer lhs = *this;
	if ((lhs.integer == -1 && rhs.integer != -1) ||
		(lhs.integer != -1 && rhs.integer == -1))
	{
		return false;
	}
	if(lhs.integer == -1 && rhs.integer == -1)
        return true;
	return lhs.integer <= rhs.integer;
}
bool Integer::operator==(const Integer& rhs) const
{
	Integer lhs = *this;
	if(lhs.integer == -1 && rhs.integer == -1)
        return true;
	return lhs.integer == rhs.integer;
}
bool Integer::operator!=(const Integer& rhs) const
{
	Integer lhs = *this;
	if((lhs.integer == -1 && rhs.integer != -1) || ((lhs.integer != -1 && rhs.integer == -1)))
        return true;

	return lhs.integer != rhs.integer;
}

Integer Integer::operator+(const Integer& rhs) const
{
	Integer lhs = *this;
	int x = lhs.integer + rhs.integer;
	if (lhs.integer < 0 || rhs.integer < 0 || x > 1000)
	{
		lhs.integer = -1;
		lhs.word = "INVALID";
		lhs.roman = "INVALID";
		return lhs;
	}
	lhs.integer = x;
	Integer i(lhs.integer);
	lhs.word = i.toWordNumber();
	lhs.roman = i.toRomanNumeral();

	return lhs;
}
Integer Integer::operator-(const Integer& rhs) const
{
	Integer lhs = *this;
	int x = lhs.integer - rhs.integer;
	if (lhs.integer < 0 || rhs.integer < 0 || x < 0)
	{
		lhs.integer = -1;
		lhs.word = "INVALID";
		lhs.roman = "INVALID";
		return lhs;
	}
	lhs.integer = x;
	Integer i(lhs.integer);
	lhs.word = i.toWordNumber();
	lhs.roman = i.toRomanNumeral();

	return lhs;
}
Integer Integer::operator* (const Integer& rhs) const
{
	Integer lhs = *this;
	int x = lhs.integer * rhs.integer;
	if (lhs.integer < 0 || rhs.integer < 0 || x > 1000)
	{
		lhs.integer = -1;
		lhs.word = "INVALID";
		lhs.roman = "INVALID";
		return lhs;
	}
	lhs.integer = x;
	Integer i(lhs.integer);
	lhs.word = i.toWordNumber();
	lhs.roman = i.toRomanNumeral();

	return lhs;
}
Integer Integer::operator/(const Integer& rhs) const
{
	Integer lhs = *this;
	if (lhs.integer < 0 || rhs.integer < 0 || rhs.integer == 0)
	{
		lhs.integer = -1;
		lhs.word = "INVALID";
		lhs.roman = "INVALID";
		return lhs;
	}
	lhs.integer = lhs.integer / rhs.integer;
	Integer i(lhs.integer);
	lhs.word = i.toWordNumber();
	lhs.roman = i.toRomanNumeral();

	return lhs;
}
Integer Integer::operator%(const Integer& rhs) const
{
	Integer lhs = *this;
	if (lhs.integer < 0 || rhs.integer < 0)
	{
		lhs.integer = -1;
		lhs.word = "INVALID";
		lhs.roman = "INVALID";
		return lhs;
	}
	lhs.integer = lhs.integer % rhs.integer;
	Integer i(lhs.integer);
	lhs.word = i.toWordNumber();
	lhs.roman = i.toRomanNumeral();

	return lhs;
}
